import datetime
import json
from unittest import mock

import graphene
import pytest
from django.conf import settings
from django.utils import timezone
from django.utils.functional import SimpleLazyObject
from django.utils.text import slugify
from freezegun import freeze_time

from .....channel.error_codes import ChannelErrorCode
from .....channel.models import Channel
from .....core.utils.json_serializer import CustomJsonEncoder
from .....tax.models import TaxConfiguration
from .....webhook.event_types import WebhookEventAsyncType
from .....webhook.payloads import generate_meta, generate_requestor
from ....tests.utils import assert_no_permission, get_graphql_content
from ...enums import (
    AllocationStrategyEnum,
    MarkAsPaidStrategyEnum,
    TransactionFlowStrategyEnum,
)

CHANNEL_CREATE_MUTATION = """
    mutation CreateChannel($input: ChannelCreateInput!){
        channelCreate(input: $input){
            channel{
                id
                name
                slug
                currencyCode
                defaultCountry {
                    code
                    country
                }
                warehouses {
                    slug
                }
                stockSettings {
                    allocationStrategy
                }
                orderSettings {
                    automaticallyConfirmAllNewOrders
                    automaticallyFulfillNonShippableGiftCard
                    expireOrdersAfter
                    markAsPaidStrategy
                    deleteExpiredOrdersAfter
                    allowUnpaidOrders
                    includeDraftOrderInVoucherUsage
                    draftOrderLinePriceFreezePeriod
                    useLegacyLineDiscountPropagation
                }
                checkoutSettings {
                    useLegacyErrorFlow
                    automaticallyCompleteFullyPaidCheckouts
                    automaticCompletionDelay
                    automaticCompletionCutOffDate
                }
                paymentSettings {
                    defaultTransactionFlowStrategy
                    releaseFundsForExpiredCheckouts
                    checkoutTtlBeforeReleasingFunds
                    checkoutReleaseFundsCutOffDate
                }
            }
            errors{
                field
                code
                message
            }
        }
    }
"""


def test_channel_create_mutation_as_staff_user(
    permission_manage_channels,
    staff_api_client,
):
    # given
    name = "testName"
    slug = "test_slug"
    currency_code = "USD"
    default_country = "US"
    allocation_strategy = AllocationStrategyEnum.PRIORITIZE_HIGH_STOCK.name
    variables = {
        "input": {
            "name": name,
            "slug": slug,
            "currencyCode": currency_code,
            "defaultCountry": default_country,
            "stockSettings": {"allocationStrategy": allocation_strategy},
            "orderSettings": {
                "automaticallyConfirmAllNewOrders": False,
                "automaticallyFulfillNonShippableGiftCard": False,
                "expireOrdersAfter": 10,
                "includeDraftOrderInVoucherUsage": True,
                "draftOrderLinePriceFreezePeriod": 10,
            },
            "checkoutSettings": {"useLegacyErrorFlow": False},
        }
    }

    # when
    response = staff_api_client.post_graphql(
        CHANNEL_CREATE_MUTATION,
        variables=variables,
        permissions=(permission_manage_channels,),
    )
    content = get_graphql_content(response)

    # then
    data = content["data"]["channelCreate"]
    assert not data["errors"]
    channel_data = data["channel"]
    channel = Channel.objects.get()
    assert channel_data["name"] == channel.name == name
    assert channel_data["slug"] == channel.slug == slug
    assert channel_data["currencyCode"] == channel.currency_code == currency_code
    assert (
        channel_data["defaultCountry"]["code"]
        == channel.default_country.code
        == default_country
    )
    assert channel_data["stockSettings"]["allocationStrategy"] == allocation_strategy
    assert channel_data["orderSettings"]["automaticallyConfirmAllNewOrders"] is False
    assert (
        channel_data["orderSettings"]["automaticallyFulfillNonShippableGiftCard"]
        is False
    )
    assert channel_data["orderSettings"]["expireOrdersAfter"] == 10
    assert channel_data["orderSettings"]["includeDraftOrderInVoucherUsage"] is True
    assert channel_data["orderSettings"]["draftOrderLinePriceFreezePeriod"] == 10
    assert channel_data["checkoutSettings"]["useLegacyErrorFlow"] is False
    assert (
        channel_data["checkoutSettings"]["automaticallyCompleteFullyPaidCheckouts"]
        is False
    )


@freeze_time("2022-05-12 12:00:00")
def test_channel_create_mutation_as_app(
    permission_manage_channels,
    app_api_client,
):
    # given
    name = "testName"
    slug = "test_slug"
    currency_code = "USD"
    default_country = "US"
    variables = {
        "input": {
            "name": name,
            "slug": slug,
            "currencyCode": currency_code,
            "defaultCountry": default_country,
            "checkoutSettings": {
                "useLegacyErrorFlow": False,
                "automaticallyCompleteFullyPaidCheckouts": True,
            },
        }
    }

    # when
    response = app_api_client.post_graphql(
        CHANNEL_CREATE_MUTATION,
        variables=variables,
        permissions=(permission_manage_channels,),
    )
    content = get_graphql_content(response)

    # then
    data = content["data"]["channelCreate"]
    assert not data["errors"]
    channel_data = data["channel"]
    channel = Channel.objects.get()
    assert channel_data["name"] == channel.name == name
    assert channel_data["slug"] == channel.slug == slug
    assert channel_data["currencyCode"] == channel.currency_code == currency_code
    assert (
        channel_data["defaultCountry"]["code"]
        == channel.default_country.code
        == default_country
    )
    assert (
        channel_data["stockSettings"]["allocationStrategy"]
        == AllocationStrategyEnum.PRIORITIZE_SORTING_ORDER.name
    )
    assert channel_data["orderSettings"]["automaticallyConfirmAllNewOrders"] is True
    assert (
        channel_data["orderSettings"]["automaticallyFulfillNonShippableGiftCard"]
        is True
    )
    assert channel_data["orderSettings"]["expireOrdersAfter"] is None
    assert channel_data["orderSettings"]["includeDraftOrderInVoucherUsage"] is False
    assert channel_data["orderSettings"]["draftOrderLinePriceFreezePeriod"] == 24
    assert channel_data["checkoutSettings"]["useLegacyErrorFlow"] is False
    assert (
        channel_data["checkoutSettings"]["automaticallyCompleteFullyPaidCheckouts"]
        is True
    )
    assert (
        channel_data["checkoutSettings"]["automaticCompletionDelay"]
        == settings.DEFAULT_AUTOMATIC_CHECKOUT_COMPLETION_DELAY
    )
    assert (
        channel_data["checkoutSettings"]["automaticCompletionCutOffDate"]
        == timezone.now().isoformat()
    )


def test_channel_create_mutation_as_customer(user_api_client):
    # given
    name = "testName"
    slug = "test_slug"
    currency_code = "USD"
    default_country = "US"
    allocation_strategy = AllocationStrategyEnum.PRIORITIZE_SORTING_ORDER.name
    variables = {
        "input": {
            "name": name,
            "slug": slug,
            "currencyCode": currency_code,
            "defaultCountry": default_country,
            "stockSettings": {"allocationStrategy": allocation_strategy},
            "orderSettings": {
                "automaticallyConfirmAllNewOrders": False,
                "automaticallyFulfillNonShippableGiftCard": False,
            },
        }
    }

    # when
    response = user_api_client.post_graphql(
        CHANNEL_CREATE_MUTATION,
        variables=variables,
        permissions=(),
    )

    # then
    assert_no_permission(response)


def test_channel_create_mutation_negative_expire_orders(
    permission_manage_channels,
    app_api_client,
):
    # given
    name = "testName"
    slug = "test_slug"
    currency_code = "USD"
    default_country = "US"
    allocation_strategy = AllocationStrategyEnum.PRIORITIZE_SORTING_ORDER.name
    variables = {
        "input": {
            "name": name,
            "slug": slug,
            "currencyCode": currency_code,
            "defaultCountry": default_country,
            "stockSettings": {"allocationStrategy": allocation_strategy},
            "orderSettings": {
                "expireOrdersAfter": -1,
            },
        }
    }

    # when
    response = app_api_client.post_graphql(
        CHANNEL_CREATE_MUTATION,
        variables=variables,
        permissions=(permission_manage_channels,),
    )

    # then
    content = get_graphql_content(response)
    error = content["data"]["channelCreate"]["errors"][0]
    assert error["field"] == "expireOrdersAfter"
    assert error["code"] == ChannelErrorCode.INVALID.name


def test_channel_create_draft_order_line_price_freeze_period_negative_value(
    permission_manage_channels,
    app_api_client,
):
    # given
    name = "testName"
    slug = "test_slug"
    currency_code = "USD"
    default_country = "US"
    allocation_strategy = AllocationStrategyEnum.PRIORITIZE_SORTING_ORDER.name
    variables = {
        "input": {
            "name": name,
            "slug": slug,
            "currencyCode": currency_code,
            "defaultCountry": default_country,
            "stockSettings": {"allocationStrategy": allocation_strategy},
            "orderSettings": {
                "draftOrderLinePriceFreezePeriod": -1,
            },
        }
    }

    # when
    response = app_api_client.post_graphql(
        CHANNEL_CREATE_MUTATION,
        variables=variables,
        permissions=(permission_manage_channels,),
    )

    # then
    content = get_graphql_content(response)
    error = content["data"]["channelCreate"]["errors"][0]
    assert error["field"] == "draftOrderLinePriceFreezePeriod"
    assert error["code"] == ChannelErrorCode.INVALID.name


@pytest.mark.parametrize("expire_input", [0, None])
def test_channel_create_mutation_disabled_expire_orders(
    expire_input,
    permission_manage_channels,
    app_api_client,
):
    # given
    name = "testName"
    slug = "test_slug"
    currency_code = "USD"
    default_country = "US"
    allocation_strategy = AllocationStrategyEnum.PRIORITIZE_SORTING_ORDER.name
    variables = {
        "input": {
            "name": name,
            "slug": slug,
            "currencyCode": currency_code,
            "defaultCountry": default_country,
            "stockSettings": {"allocationStrategy": allocation_strategy},
            "orderSettings": {
                "expireOrdersAfter": expire_input,
            },
        }
    }

    # when
    response = app_api_client.post_graphql(
        CHANNEL_CREATE_MUTATION,
        variables=variables,
        permissions=(permission_manage_channels,),
    )

    # then
    content = get_graphql_content(response)
    data = content["data"]["channelCreate"]
    assert not data["errors"]
    assert data["channel"]["orderSettings"]["expireOrdersAfter"] is None


def test_channel_create_mutation_as_anonymous(api_client):
    # given
    name = "testName"
    slug = "test_slug"
    currency_code = "USD"
    default_country = "US"
    variables = {
        "input": {
            "name": name,
            "slug": slug,
            "currencyCode": currency_code,
            "defaultCountry": default_country,
        }
    }

    # when
    response = api_client.post_graphql(
        CHANNEL_CREATE_MUTATION,
        variables=variables,
        permissions=(),
    )

    # then
    assert_no_permission(response)


def test_channel_create_mutation_slugify_slug_field(
    permission_manage_channels,
    staff_api_client,
):
    # given
    name = "testName"
    slug = "Invalid slug"
    currency_code = "USD"
    default_country = "US"
    variables = {
        "input": {
            "name": name,
            "slug": slug,
            "currencyCode": currency_code,
            "defaultCountry": default_country,
        }
    }

    # when
    response = staff_api_client.post_graphql(
        CHANNEL_CREATE_MUTATION,
        variables=variables,
        permissions=(permission_manage_channels,),
    )
    content = get_graphql_content(response)

    # then
    channel_data = content["data"]["channelCreate"]["channel"]
    assert channel_data["slug"] == slugify(slug)


def test_channel_create_mutation_with_duplicated_slug(
    permission_manage_channels, staff_api_client, channel_USD
):
    # given
    name = "New Channel"
    slug = channel_USD.slug
    currency_code = "USD"
    default_country = "US"
    allocation_strategy = AllocationStrategyEnum.PRIORITIZE_SORTING_ORDER.name
    variables = {
        "input": {
            "name": name,
            "slug": slug,
            "currencyCode": currency_code,
            "defaultCountry": default_country,
            "stockSettings": {"allocationStrategy": allocation_strategy},
        }
    }

    # when
    response = staff_api_client.post_graphql(
        CHANNEL_CREATE_MUTATION,
        variables=variables,
        permissions=(permission_manage_channels,),
    )
    content = get_graphql_content(response)

    # then
    error = content["data"]["channelCreate"]["errors"][0]
    assert error["field"] == "slug"
    assert error["code"] == ChannelErrorCode.UNIQUE.name


def test_channel_create_mutation_with_shipping_zones(
    permission_manage_channels,
    staff_api_client,
    shipping_zones,
):
    # given
    name = "testName"
    slug = "test_slug"
    currency_code = "USD"
    default_country = "US"
    shipping_zones_ids = [
        graphene.Node.to_global_id("ShippingZone", zone.pk) for zone in shipping_zones
    ]
    allocation_strategy = AllocationStrategyEnum.PRIORITIZE_SORTING_ORDER.name
    variables = {
        "input": {
            "name": name,
            "slug": slug,
            "currencyCode": currency_code,
            "addShippingZones": shipping_zones_ids,
            "defaultCountry": default_country,
            "stockSettings": {"allocationStrategy": allocation_strategy},
        }
    }

    # when
    response = staff_api_client.post_graphql(
        CHANNEL_CREATE_MUTATION,
        variables=variables,
        permissions=(permission_manage_channels,),
    )
    content = get_graphql_content(response)

    # then
    data = content["data"]["channelCreate"]
    assert not data["errors"]
    channel_data = data["channel"]
    channel = Channel.objects.get(
        id=graphene.Node.from_global_id(channel_data["id"])[1]
    )
    assert channel_data["name"] == channel.name == name
    assert channel_data["slug"] == channel.slug == slug
    assert channel_data["currencyCode"] == channel.currency_code == currency_code
    for shipping_zone in shipping_zones:
        shipping_zone.channels.get(slug=slug)
    assert channel_data["stockSettings"]["allocationStrategy"] == allocation_strategy


def test_channel_create_mutation_with_warehouses(
    permission_manage_channels,
    staff_api_client,
    warehouses,
):
    # given
    name = "testName"
    slug = "test_slug"
    currency_code = "USD"
    default_country = "US"
    warehouses_ids = [
        graphene.Node.to_global_id("Warehouse", warehouse.pk)
        for warehouse in warehouses
    ]
    allocation_strategy = AllocationStrategyEnum.PRIORITIZE_SORTING_ORDER.name
    variables = {
        "input": {
            "name": name,
            "slug": slug,
            "currencyCode": currency_code,
            "addWarehouses": warehouses_ids,
            "defaultCountry": default_country,
            "stockSettings": {"allocationStrategy": allocation_strategy},
        }
    }

    # when
    response = staff_api_client.post_graphql(
        CHANNEL_CREATE_MUTATION,
        variables=variables,
        permissions=(permission_manage_channels,),
    )
    content = get_graphql_content(response)

    # then
    data = content["data"]["channelCreate"]
    assert not data["errors"]
    channel_data = data["channel"]
    channel = Channel.objects.get(
        id=graphene.Node.from_global_id(channel_data["id"])[1]
    )
    assert channel_data["name"] == channel.name == name
    assert channel_data["slug"] == channel.slug == slug
    assert channel_data["currencyCode"] == channel.currency_code == currency_code
    assert {
        warehouse_data["slug"] for warehouse_data in channel_data["warehouses"]
    } == {warehouse.slug for warehouse in warehouses}
    assert channel_data["stockSettings"]["allocationStrategy"] == allocation_strategy


@freeze_time("2022-05-12 12:00:00")
@mock.patch("saleor.plugins.webhook.plugin.get_webhooks_for_event")
@mock.patch("saleor.plugins.webhook.plugin.trigger_webhooks_async")
def test_channel_create_mutation_trigger_webhook(
    mocked_webhook_trigger,
    mocked_get_webhooks_for_event,
    any_webhook,
    permission_manage_channels,
    staff_api_client,
    settings,
):
    # given
    mocked_get_webhooks_for_event.return_value = [any_webhook]
    settings.PLUGINS = ["saleor.plugins.webhook.plugin.WebhookPlugin"]

    name = "testName"
    slug = "test_slug"
    currency_code = "USD"
    default_country = "US"
    allocation_strategy = AllocationStrategyEnum.PRIORITIZE_SORTING_ORDER.name
    variables = {
        "input": {
            "name": name,
            "slug": slug,
            "currencyCode": currency_code,
            "defaultCountry": default_country,
            "stockSettings": {"allocationStrategy": allocation_strategy},
        }
    }

    # when
    response = staff_api_client.post_graphql(
        CHANNEL_CREATE_MUTATION,
        variables=variables,
        permissions=(permission_manage_channels,),
    )
    content = get_graphql_content(response)
    channel = Channel.objects.last()
    data = content["data"]["channelCreate"]

    # then
    assert data["channel"]
    assert not data["errors"]

    mocked_webhook_trigger.assert_called_once_with(
        json.dumps(
            {
                "id": graphene.Node.to_global_id("Channel", channel.id),
                "is_active": channel.is_active,
                "meta": generate_meta(
                    requestor_data=generate_requestor(
                        SimpleLazyObject(lambda: staff_api_client.user)
                    )
                ),
            },
            cls=CustomJsonEncoder,
        ),
        WebhookEventAsyncType.CHANNEL_CREATED,
        [any_webhook],
        channel,
        SimpleLazyObject(lambda: staff_api_client.user),
        allow_replica=False,
    )


def test_channel_create_creates_tax_configuration(
    permission_manage_channels, staff_api_client
):
    # given
    slug = "channel-with-tax-config"
    variables = {
        "input": {
            "name": "Channel with tax config",
            "slug": slug,
            "currencyCode": "USD",
            "defaultCountry": "US",
        }
    }

    # when
    staff_api_client.post_graphql(
        CHANNEL_CREATE_MUTATION,
        variables=variables,
        permissions=(permission_manage_channels,),
    )

    # then
    channel = Channel.objects.get(slug=slug)
    assert TaxConfiguration.objects.filter(channel=channel).exists()


def test_channel_create_set_order_mark_as_paid(
    permission_manage_channels,
    staff_api_client,
):
    # given
    name = "testName"
    slug = "test_slug"
    currency_code = "USD"
    default_country = "US"
    variables = {
        "input": {
            "name": name,
            "slug": slug,
            "currencyCode": currency_code,
            "defaultCountry": default_country,
            "orderSettings": {
                "markAsPaidStrategy": MarkAsPaidStrategyEnum.TRANSACTION_FLOW.name
            },
        }
    }

    # when
    response = staff_api_client.post_graphql(
        CHANNEL_CREATE_MUTATION,
        variables=variables,
        permissions=(permission_manage_channels,),
    )
    content = get_graphql_content(response)

    # then
    data = content["data"]["channelCreate"]
    assert not data["errors"]
    channel_data = data["channel"]
    channel = Channel.objects.get()
    assert (
        channel_data["orderSettings"]["markAsPaidStrategy"]
        == MarkAsPaidStrategyEnum.TRANSACTION_FLOW.name
    )
    assert (
        channel.order_mark_as_paid_strategy
        == MarkAsPaidStrategyEnum.TRANSACTION_FLOW.value
    )


def test_channel_create_set_default_transaction_flow_strategy(
    permission_manage_channels,
    staff_api_client,
):
    # given
    name = "testName"
    slug = "test_slug"
    currency_code = "USD"
    default_country = "US"
    variables = {
        "input": {
            "name": name,
            "slug": slug,
            "currencyCode": currency_code,
            "defaultCountry": default_country,
            "paymentSettings": {
                "defaultTransactionFlowStrategy": (
                    TransactionFlowStrategyEnum.AUTHORIZATION.name
                )
            },
        }
    }

    # when
    response = staff_api_client.post_graphql(
        CHANNEL_CREATE_MUTATION,
        variables=variables,
        permissions=(permission_manage_channels,),
    )
    content = get_graphql_content(response)

    # then
    data = content["data"]["channelCreate"]
    assert not data["errors"]
    channel_data = data["channel"]
    channel = Channel.objects.get()
    assert (
        channel_data["paymentSettings"]["defaultTransactionFlowStrategy"]
        == TransactionFlowStrategyEnum.AUTHORIZATION.name
    )
    assert (
        channel.default_transaction_flow_strategy
        == TransactionFlowStrategyEnum.AUTHORIZATION.value
    )


def test_channel_create_set_checkout_release_settings(
    permission_manage_channels,
    staff_api_client,
):
    # given
    name = "testName"
    slug = "test_slug"
    currency_code = "USD"
    default_country = "US"

    date = datetime.datetime(2022, 5, 12, 0, 0, 0, tzinfo=datetime.UTC)
    ttl_before_releasing_funds = 7
    variables = {
        "input": {
            "name": name,
            "slug": slug,
            "currencyCode": currency_code,
            "defaultCountry": default_country,
            "paymentSettings": {
                "releaseFundsForExpiredCheckouts": False,
                "checkoutTtlBeforeReleasingFunds": ttl_before_releasing_funds,
                "checkoutReleaseFundsCutOffDate": date,
            },
        }
    }

    # when
    response = staff_api_client.post_graphql(
        CHANNEL_CREATE_MUTATION,
        variables=variables,
        permissions=(permission_manage_channels,),
    )
    content = get_graphql_content(response)

    # then
    data = content["data"]["channelCreate"]
    assert not data["errors"]
    channel_data = data["channel"]
    channel = Channel.objects.get()
    assert not channel_data["paymentSettings"]["releaseFundsForExpiredCheckouts"]
    assert (
        channel_data["paymentSettings"]["checkoutTtlBeforeReleasingFunds"]
        == ttl_before_releasing_funds
    )
    assert (
        channel_data["paymentSettings"]["checkoutReleaseFundsCutOffDate"]
        == "2022-05-12T00:00:00+00:00"
    )

    assert not channel.release_funds_for_expired_checkouts
    assert channel.checkout_ttl_before_releasing_funds == datetime.timedelta(
        hours=ttl_before_releasing_funds
    )
    assert channel.checkout_release_funds_cut_off_date == date


def test_channel_create_set_incorect_checkout_ttl_before_releasing_funds(
    permission_manage_channels,
    staff_api_client,
):
    # given
    name = "testName"
    slug = "test_slug"
    currency_code = "USD"
    default_country = "US"

    ttl_before_releasing_funds = 0
    variables = {
        "input": {
            "name": name,
            "slug": slug,
            "currencyCode": currency_code,
            "defaultCountry": default_country,
            "paymentSettings": {
                "checkoutTtlBeforeReleasingFunds": ttl_before_releasing_funds,
            },
        }
    }

    # when
    response = staff_api_client.post_graphql(
        CHANNEL_CREATE_MUTATION,
        variables=variables,
        permissions=(permission_manage_channels,),
    )
    content = get_graphql_content(response)

    # then
    errors = content["data"]["channelCreate"]["errors"]
    assert len(errors) == 1
    assert errors[0]["field"] == "checkoutTtlBeforeReleasingFunds"
    assert errors[0]["code"] == ChannelErrorCode.INVALID.name


def test_channel_create_set_delete_expired_orders_after(
    permission_manage_channels,
    staff_api_client,
):
    # given
    name = "testName"
    slug = "test_slug"
    currency_code = "USD"
    default_country = "US"
    delete_expired_after = 10
    variables = {
        "input": {
            "name": name,
            "slug": slug,
            "currencyCode": currency_code,
            "defaultCountry": default_country,
            "orderSettings": {"deleteExpiredOrdersAfter": delete_expired_after},
        }
    }

    # when
    response = staff_api_client.post_graphql(
        CHANNEL_CREATE_MUTATION,
        variables=variables,
        permissions=(permission_manage_channels,),
    )
    content = get_graphql_content(response)

    # then
    data = content["data"]["channelCreate"]
    assert not data["errors"]
    channel_data = data["channel"]
    channel = Channel.objects.get()
    assert (
        channel_data["orderSettings"]["deleteExpiredOrdersAfter"]
        == delete_expired_after
    )
    assert channel.delete_expired_orders_after == datetime.timedelta(
        days=delete_expired_after
    )


@pytest.mark.parametrize("delete_expired_after", [-1, 0, 121, 300])
def test_channel_create_mutation_set_incorrect_delete_expired_orders_after(
    delete_expired_after, permission_manage_channels, staff_api_client, channel_USD
):
    # given
    name = "testName"
    slug = "test_slug"
    currency_code = "USD"
    default_country = "US"
    variables = {
        "input": {
            "name": name,
            "slug": slug,
            "currencyCode": currency_code,
            "defaultCountry": default_country,
            "orderSettings": {"deleteExpiredOrdersAfter": delete_expired_after},
        }
    }

    # when
    response = staff_api_client.post_graphql(
        CHANNEL_CREATE_MUTATION,
        variables=variables,
        permissions=(permission_manage_channels,),
    )
    content = get_graphql_content(response)

    # then
    error = content["data"]["channelCreate"]["errors"][0]
    assert error["field"] == "deleteExpiredOrdersAfter"
    assert error["code"] == ChannelErrorCode.INVALID.name


def test_channel_create_set_checkout_use_legacy_error_flow(
    permission_manage_channels,
    staff_api_client,
):
    # given
    name = "testName"
    slug = "test_slug"
    currency_code = "USD"
    default_country = "US"
    variables = {
        "input": {
            "name": name,
            "slug": slug,
            "currencyCode": currency_code,
            "defaultCountry": default_country,
            "checkoutSettings": {"useLegacyErrorFlow": False},
        }
    }

    # when
    response = staff_api_client.post_graphql(
        CHANNEL_CREATE_MUTATION,
        variables=variables,
        permissions=(permission_manage_channels,),
    )
    content = get_graphql_content(response)

    # then
    data = content["data"]["channelCreate"]
    assert not data["errors"]
    channel_data = data["channel"]
    channel = Channel.objects.get()
    assert channel_data["checkoutSettings"]["useLegacyErrorFlow"] is False
    assert channel.use_legacy_error_flow_for_checkout is False


@freeze_time("2022-05-12 12:00:00")
def test_channel_create_set_automatic_checkout_completion(
    permission_manage_channels,
    staff_api_client,
):
    # given
    name = "testName"
    slug = "test_slug"
    currency_code = "USD"
    default_country = "US"
    variables = {
        "input": {
            "name": name,
            "slug": slug,
            "currencyCode": currency_code,
            "defaultCountry": default_country,
            "checkoutSettings": {
                "automaticallyCompleteFullyPaidCheckouts": True,
            },
        }
    }

    # when
    response = staff_api_client.post_graphql(
        CHANNEL_CREATE_MUTATION,
        variables=variables,
        permissions=(permission_manage_channels,),
    )
    content = get_graphql_content(response)

    # then
    data = content["data"]["channelCreate"]
    assert not data["errors"]
    channel_data = data["channel"]
    channel = Channel.objects.get()
    assert (
        channel_data["checkoutSettings"]["automaticallyCompleteFullyPaidCheckouts"]
        is True
    )
    assert (
        channel_data["checkoutSettings"]["automaticCompletionDelay"]
        == settings.DEFAULT_AUTOMATIC_CHECKOUT_COMPLETION_DELAY
    )
    assert (
        channel_data["checkoutSettings"]["automaticCompletionCutOffDate"]
        == timezone.now().isoformat()
    )

    assert channel.automatically_complete_fully_paid_checkouts is True
    assert (
        channel.automatic_completion_delay
        == settings.DEFAULT_AUTOMATIC_CHECKOUT_COMPLETION_DELAY
    )
    assert channel.automatic_completion_cut_off_date == timezone.now()


def test_channel_create_set_automatic_checkout_completion_false(
    permission_manage_channels,
    staff_api_client,
):
    # given
    name = "testName"
    slug = "test_slug"
    currency_code = "USD"
    default_country = "US"
    variables = {
        "input": {
            "name": name,
            "slug": slug,
            "currencyCode": currency_code,
            "defaultCountry": default_country,
            "checkoutSettings": {
                "automaticallyCompleteFullyPaidCheckouts": False,
            },
        }
    }

    # when
    response = staff_api_client.post_graphql(
        CHANNEL_CREATE_MUTATION,
        variables=variables,
        permissions=(permission_manage_channels,),
    )
    content = get_graphql_content(response)

    # then
    data = content["data"]["channelCreate"]
    assert not data["errors"]
    channel = Channel.objects.get()
    assert channel.automatically_complete_fully_paid_checkouts is False
    assert channel.automatic_completion_delay is None
    assert channel.automatic_completion_cut_off_date is None


def test_channel_create_with_automatic_completion_delay_value_below_0(
    permission_manage_channels,
    staff_api_client,
):
    # given
    name = "testName"
    slug = "test_slug"
    currency_code = "USD"
    default_country = "US"
    variables = {
        "input": {
            "name": name,
            "slug": slug,
            "currencyCode": currency_code,
            "defaultCountry": default_country,
            "checkoutSettings": {
                "automaticCompletion": {
                    "enabled": True,
                    "delay": -1,
                }
            },
        }
    }

    # when
    response = staff_api_client.post_graphql(
        CHANNEL_CREATE_MUTATION,
        variables=variables,
        permissions=(permission_manage_channels,),
    )
    content = get_graphql_content(response)

    # then
    error = content["data"]["channelCreate"]["errors"][0]
    assert error["field"] == "delay"
    assert error["code"] == ChannelErrorCode.INVALID.name


def test_channel_create_with_delay_exceeding_threshold(
    permission_manage_channels,
    staff_api_client,
    settings,
):
    # given
    name = "testName"
    slug = "test_slug"
    currency_code = "USD"
    default_country = "US"
    oldest_allowed_checkout = (
        settings.AUTOMATIC_CHECKOUT_COMPLETION_OLDEST_MODIFIED.total_seconds() // 60
    )
    variables = {
        "input": {
            "name": name,
            "slug": slug,
            "currencyCode": currency_code,
            "defaultCountry": default_country,
            "checkoutSettings": {
                "automaticCompletion": {
                    "enabled": True,
                    "delay": oldest_allowed_checkout + 1,  # Exceeds threshold
                },
            },
        }
    }

    # when
    response = staff_api_client.post_graphql(
        CHANNEL_CREATE_MUTATION,
        variables=variables,
        permissions=(permission_manage_channels,),
    )
    content = get_graphql_content(response)

    # then
    data = content["data"]["channelCreate"]
    assert data["errors"]
    assert data["errors"][0]["field"] == "delay"
    assert data["errors"][0]["code"] == ChannelErrorCode.INVALID.name


@freeze_time("2022-05-12 12:00:00")
def test_channel_create_with_new_automatic_completion_enabled_with_default_delay(
    permission_manage_channels,
    staff_api_client,
):
    # given
    name = "testName"
    slug = "test_slug"
    currency_code = "USD"
    default_country = "US"
    variables = {
        "input": {
            "name": name,
            "slug": slug,
            "currencyCode": currency_code,
            "defaultCountry": default_country,
            "checkoutSettings": {
                "automaticCompletion": {
                    "enabled": True,
                }
            },
        }
    }

    # when
    response = staff_api_client.post_graphql(
        CHANNEL_CREATE_MUTATION,
        variables=variables,
        permissions=(permission_manage_channels,),
    )
    content = get_graphql_content(response)

    # then
    data = content["data"]["channelCreate"]
    assert not data["errors"]
    channel_data = data["channel"]
    channel = Channel.objects.get()
    assert (
        channel_data["checkoutSettings"]["automaticallyCompleteFullyPaidCheckouts"]
        is True
    )
    default_delay = settings.DEFAULT_AUTOMATIC_CHECKOUT_COMPLETION_DELAY
    assert channel_data["checkoutSettings"]["automaticCompletionDelay"] == default_delay
    assert channel.automatically_complete_fully_paid_checkouts is True
    assert channel.automatic_completion_delay == default_delay
    assert channel.automatic_completion_cut_off_date == timezone.now()


def test_channel_create_with_new_automatic_completion_enabled_with_custom_delay_and_cut_off(
    permission_manage_channels,
    staff_api_client,
):
    # given
    name = "testName"
    slug = "test_slug"
    currency_code = "USD"
    default_country = "US"
    delay = 15
    cut_off = timezone.now() + datetime.timedelta(days=2)
    variables = {
        "input": {
            "name": name,
            "slug": slug,
            "currencyCode": currency_code,
            "defaultCountry": default_country,
            "checkoutSettings": {
                "automaticCompletion": {
                    "enabled": True,
                    "delay": delay,
                    "cutOffDate": cut_off.isoformat(),
                }
            },
        }
    }

    # when
    response = staff_api_client.post_graphql(
        CHANNEL_CREATE_MUTATION,
        variables=variables,
        permissions=(permission_manage_channels,),
    )
    content = get_graphql_content(response)

    # then
    data = content["data"]["channelCreate"]
    assert not data["errors"]
    channel_data = data["channel"]
    channel = Channel.objects.get()
    assert (
        channel_data["checkoutSettings"]["automaticallyCompleteFullyPaidCheckouts"]
        is True
    )
    assert channel_data["checkoutSettings"]["automaticCompletionDelay"] == delay
    assert (
        channel_data["checkoutSettings"]["automaticCompletionCutOffDate"]
        == cut_off.isoformat()
    )
    assert channel.automatically_complete_fully_paid_checkouts is True
    assert channel.automatic_completion_delay == delay
    assert channel.automatic_completion_cut_off_date == cut_off


def test_channel_create_with_automatic_completion_disabled(
    permission_manage_channels,
    staff_api_client,
):
    # given
    name = "testName"
    slug = "test_slug"
    currency_code = "USD"
    default_country = "US"
    variables = {
        "input": {
            "name": name,
            "slug": slug,
            "currencyCode": currency_code,
            "defaultCountry": default_country,
            "checkoutSettings": {
                "automaticCompletion": {
                    "enabled": False,
                }
            },
        }
    }

    # when
    response = staff_api_client.post_graphql(
        CHANNEL_CREATE_MUTATION,
        variables=variables,
        permissions=(permission_manage_channels,),
    )
    content = get_graphql_content(response)

    # then
    data = content["data"]["channelCreate"]
    assert not data["errors"]
    channel = Channel.objects.get()
    assert channel.automatically_complete_fully_paid_checkouts is False
    assert channel.automatic_completion_delay is None
    assert channel.automatic_completion_cut_off_date is None


def test_channel_create_with_automatic_completion_disabled_and_delay(
    permission_manage_channels,
    staff_api_client,
):
    # given
    name = "testName"
    slug = "test_slug"
    currency_code = "USD"
    default_country = "US"
    variables = {
        "input": {
            "name": name,
            "slug": slug,
            "currencyCode": currency_code,
            "defaultCountry": default_country,
            "checkoutSettings": {
                "automaticCompletion": {
                    "enabled": False,
                    "delay": 10,
                }
            },
        }
    }

    # when
    response = staff_api_client.post_graphql(
        CHANNEL_CREATE_MUTATION,
        variables=variables,
        permissions=(permission_manage_channels,),
    )
    content = get_graphql_content(response)

    # then
    error = content["data"]["channelCreate"]["errors"][0]
    assert error["field"] == "delay"
    assert error["code"] == ChannelErrorCode.INVALID.name


def test_channel_create_with_automatic_completion_disabled_and_cutoff(
    permission_manage_channels,
    staff_api_client,
):
    # given
    name = "testName"
    slug = "test_slug"
    currency_code = "USD"
    default_country = "US"
    cut_off = datetime.datetime(2022, 5, 20, 0, 0, 0, tzinfo=datetime.UTC)
    variables = {
        "input": {
            "name": name,
            "slug": slug,
            "currencyCode": currency_code,
            "defaultCountry": default_country,
            "checkoutSettings": {
                "automaticCompletion": {
                    "enabled": False,
                    "cutOffDate": cut_off.isoformat(),
                }
            },
        }
    }

    # when
    response = staff_api_client.post_graphql(
        CHANNEL_CREATE_MUTATION,
        variables=variables,
        permissions=(permission_manage_channels,),
    )
    content = get_graphql_content(response)

    # then
    error = content["data"]["channelCreate"]["errors"][0]
    assert error["field"] == "cutOffDate"
    assert error["code"] == ChannelErrorCode.INVALID.name


def test_channel_create_with_both_old_and_new_automatic_completion_fields(
    permission_manage_channels,
    staff_api_client,
):
    # given
    name = "testName"
    slug = "test_slug"
    currency_code = "USD"
    default_country = "US"
    variables = {
        "input": {
            "name": name,
            "slug": slug,
            "currencyCode": currency_code,
            "defaultCountry": default_country,
            "checkoutSettings": {
                "automaticallyCompleteFullyPaidCheckouts": True,
                "automaticCompletion": {
                    "enabled": True,
                    "delay": 10,
                },
            },
        }
    }

    # when
    response = staff_api_client.post_graphql(
        CHANNEL_CREATE_MUTATION,
        variables=variables,
        permissions=(permission_manage_channels,),
    )
    content = get_graphql_content(response)

    # then
    error = content["data"]["channelCreate"]["errors"][0]
    assert error["field"] == "automaticallyCompleteFullyPaidCheckouts"
    assert error["code"] == ChannelErrorCode.INVALID.name


@freeze_time("2022-05-12 12:00:00")
def test_channel_create_with_cutoff_later_than_threshold(
    permission_manage_channels,
    staff_api_client,
    settings,
):
    # given
    name = "testName"
    slug = "test_slug"
    currency_code = "USD"
    default_country = "US"
    cutoff_date = (
        timezone.now()
        - settings.AUTOMATIC_CHECKOUT_COMPLETION_OLDEST_MODIFIED
        - datetime.timedelta(days=10)
    )
    variables = {
        "input": {
            "name": name,
            "slug": slug,
            "currencyCode": currency_code,
            "defaultCountry": default_country,
            "checkoutSettings": {
                "automaticCompletion": {
                    "enabled": True,
                    "cutOffDate": cutoff_date.isoformat(),
                },
            },
        }
    }

    # when
    response = staff_api_client.post_graphql(
        CHANNEL_CREATE_MUTATION,
        variables=variables,
        permissions=(permission_manage_channels,),
    )
    content = get_graphql_content(response)

    # then
    data = content["data"]["channelCreate"]
    assert data["errors"]
    assert data["errors"][0]["field"] == "cutOffDate"
    assert data["errors"][0]["code"] == ChannelErrorCode.INVALID.name


@pytest.mark.parametrize("allow_unpaid", [True, False])
def test_channel_create_set_allow_unpaid_orders(
    allow_unpaid,
    permission_manage_channels,
    staff_api_client,
):
    # given
    name = "testName"
    slug = "test_slug"
    currency_code = "USD"
    default_country = "US"
    variables = {
        "input": {
            "name": name,
            "slug": slug,
            "currencyCode": currency_code,
            "defaultCountry": default_country,
            "orderSettings": {"allowUnpaidOrders": allow_unpaid},
        }
    }

    # when
    response = staff_api_client.post_graphql(
        CHANNEL_CREATE_MUTATION,
        variables=variables,
        permissions=(permission_manage_channels,),
    )
    content = get_graphql_content(response)

    # then
    data = content["data"]["channelCreate"]
    assert not data["errors"]
    channel_data = data["channel"]
    channel = Channel.objects.get()
    assert channel_data["orderSettings"]["allowUnpaidOrders"] == allow_unpaid
    assert channel.allow_unpaid_orders == allow_unpaid


@pytest.mark.parametrize(
    ("use_legacy_input", "expected_result"),
    [
        ({"useLegacyLineDiscountPropagation": True}, True),
        ({"useLegacyLineDiscountPropagation": False}, False),
        (None, False),
        ({"allowUnpaidOrders": False}, False),
    ],
)
def test_channel_create_set_use_legacy_line_discount_propagation(
    use_legacy_input,
    expected_result,
    permission_manage_channels,
    staff_api_client,
):
    # given
    name = "testName"
    slug = "test_slug"
    currency_code = "USD"
    default_country = "US"
    variables = {
        "input": {
            "name": name,
            "slug": slug,
            "currencyCode": currency_code,
            "defaultCountry": default_country,
            "orderSettings": use_legacy_input,
        }
    }

    # when
    response = staff_api_client.post_graphql(
        CHANNEL_CREATE_MUTATION,
        variables=variables,
        permissions=(permission_manage_channels,),
    )
    content = get_graphql_content(response)

    # then
    data = content["data"]["channelCreate"]
    assert not data["errors"]
    channel_data = data["channel"]
    channel = Channel.objects.get()
    assert (
        channel_data["orderSettings"]["useLegacyLineDiscountPropagation"]
        == expected_result
    )
    assert channel.use_legacy_line_discount_propagation_for_order == expected_result
